/**
 * Copyright (C) 2009 Noel Ang
 *
 * This file is part of Samsara.
 *
 * Samsara is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Samsara is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Samsara.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package com.lunarshades.samsara.ui.actions;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.net.URL;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.prefs.Preferences;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

import com.lunarshades.samsara.Raider;
import com.lunarshades.samsara.ui.RosterTableModel;
import com.lunarshades.samsara.ui.SamsaraFrame;

/**
 * Action for loading data from a file to a RosterTableModel.
 *
 * @author Noel Ang, sparta.variable@gmail.com
 * @see com.lunarshades.samsara.ui.RosterTableModel
 */
public class LoadDataAction<E extends Raider> extends AbstractAction {

public LoadDataAction(RosterTableModel<E> pModel,
                      Class<E> elementClass,
                      SaveDataAction pSaveAction,
                      SamsaraFrame pAppFrame
) {
    super(NAME);
    mApp = pAppFrame;
    mModel = pModel;
    mElementClass = elementClass;
    mSaveAction = pSaveAction;

    URL smallIconUrl = getClass().getResource(
            "/com/lunarshades/samsara/ui/icons/open16.gif"
    );
    putValue(Action.SMALL_ICON, new ImageIcon(smallIconUrl));
    putValue(Action.SHORT_DESCRIPTION, SHORT_TEXT);
    putValue(Action.MNEMONIC_KEY, KeyEvent.VK_L);
}

private File chooseFile() {
    File targetFile = null;
    int decision = mFileChooser.showOpenDialog(mApp);
    if (decision == JFileChooser.APPROVE_OPTION) {
        targetFile = mFileChooser.getSelectedFile();
        if (!targetFile.isFile()) {
            targetFile = null;
        }
    }
    return targetFile;
}

private boolean loadData() {
    File targetFile = chooseFile();
    boolean success = false;
    if (targetFile != null) {
        if (loadData(targetFile)) {
            // Update the visual table
            //mModel.fireTableDataChanged();

            mFileStore = targetFile;
            success = true;
            mApp.postStatusMessage(MessageFormat.format(FILE_LOADED_STATUS,
                    targetFile.getName()
            )
            );
            firePropertyChange(FILE_LOADED, null, targetFile);
        }
    }
    return success;
}

private boolean loadData(File pTargetFile) {
    boolean isFileLoaded = true;
    BufferedReader reader = null;
    List<E> tableBuffer = new LinkedList<E>();
    try {
        FileReader in = new FileReader(pTargetFile);
        reader = new BufferedReader(in);
        while (true) {
            String line = reader.readLine();
            if (line == null) {
                break;
            } else {
                line = line.trim();
                if (!"".equals(line)) {
                    E item = mElementClass.newInstance();
                    item.unmarshal(line);
                    if (!tableBuffer.contains(item)) {
                        tableBuffer.add(item);
                    } else {
                        isFileLoaded = false;
                        showErrorDialog(
                                "File contains more than one record for '"
                                        + item.name()
                                        + "'."
                        );
                        break;
                    }
                }
            }
        }
    } catch (Exception e) {
        isFileLoaded = false;
        e.printStackTrace(System.err);
        showErrorDialog(e.getLocalizedMessage());
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (Exception e) {
                e.printStackTrace(System.err);
            }
        }
    }

    if (!isFileLoaded) {
        tableBuffer.clear();
    } else {
        synchronized (mModel) {
            int rowCount = mModel.getRowCount();
            for (int i = 0; i < rowCount; ++i) {
                try {
                    mModel.setRowAt(null, 0);
                } catch (Exception e) {
                    assert false;
                }
            }
            for (E raider : tableBuffer) {
                try {
                    mModel.setRowAt(raider, mModel.getRowCount());
                } catch (Exception e) {
                    assert false;
                }
            }
        }
    }
    return isFileLoaded;
}

private void showErrorDialog(String pMessage) {
    StringBuffer messageBuffer = new StringBuffer();
    messageBuffer.append("Data could not be loaded!\n");
    messageBuffer.append(pMessage);
    JOptionPane.showMessageDialog(mApp,
            messageBuffer.toString(),
            "Load canceled",
            JOptionPane.ERROR_MESSAGE
    );
}

public void savePreferences(Preferences pPrefs) {
    pPrefs.put(PREF_CWD, mFileChooser.getCurrentDirectory().getPath()
    );
}

public void loadPreferences(Preferences pPrefs) {
    String startingDirectory = mFileChooser.getCurrentDirectory().getPath();
    String currentDirectory = pPrefs.get(PREF_CWD, startingDirectory);
    if (!currentDirectory.equals(startingDirectory)) {
        File currentFile = new File(currentDirectory);
        if (currentFile.isFile()) {
            currentFile = currentFile.getParentFile();
        }
        if (currentFile != null && currentFile.isDirectory()) {
            mFileChooser.setCurrentDirectory(currentFile);
        }
    }
}

public void actionPerformed(ActionEvent e) {
    if (!mApp.isDataSaved()) {
        int decision = mApp.promptToSaveData();
        switch (decision) {
        case JOptionPane.NO_OPTION:
            // Don't save
            break;
        case JOptionPane.YES_OPTION:
            // Save
            mSaveAction.setFileStore(mFileStore);
            if (mSaveAction.execute()) {
                break;
            }
            // fall-through
        default:
            // Cancel load.
            return;
        }
    }
    loadData();
}

private static final String PREF_CWD = "CurrentLoadDirectory";
private static final String NAME = "Load ...";
private static final String SHORT_TEXT = "Load a data set from a file";
private static final String FILE_LOADED_STATUS = "Loaded {0}.";
private final Class<E> mElementClass;
private final SamsaraFrame mApp;
private final RosterTableModel<E> mModel;
private final JFileChooser mFileChooser = new JFileChooser();
private volatile File mFileStore;
private final SaveDataAction mSaveAction;

public static final String FILE_LOADED = "FileLoaded";
}
